home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fritz: All Fritz
/
All Fritz.zip
/
All Fritz
/
FILES
/
PROGBLER
/
WHIZZARD.LZH
/
COMPRINT.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-06-16
|
20KB
|
815 lines
COMMENT *
CLUBware (tm)
COMPRINT - Enhancement to the Basic Compiler Print statement
(for routines compiled without /O option)
Copyright 1984 Rayhawk Automation N.W. Inc
P.O. Box 1427
Beaverton, Oregon 97075
*
SCRDSEG SEGMENT
ASSUME CS:SCRDSEG,DS:NOTHING,ES:NOTHING,SS:STACK
ORIG_INT10 LABEL WORD ; original int 10
DW 0
DW 0
;______________________________________________________________________________
; Swap the code used by BASIC to print strings. Swap must be made
; after BASIC has been loaded and initialized its environment. When the
; screen is cleared INTSWAP intercepts the BASIC print statement.
ORIG_2841 LABEL WORD ; original subroutine 2841
DW 2846h
BASIC_SEGMENT LABEL WORD
DW 0
CALLERS_SEG EQU WORD PTR [BP+4] ; location of callers segment on stack
INTSWAP PROC FAR
CMP AX,0600h ; clear screen request?
JE DO_SWAP
JMP DWORD PTR ORIG_INT10 ; pass call to BIOS
DO_SWAP:
PUSH BP ; address the stack
MOV BP,SP
PUSH DS
PUSH AX
MOV AX,CALLERS_SEG ; address basic space
MOV DS,AX
MOV BASIC_SEGMENT,AX ; save basic's code segment
CLI ; disable interrupts for a moment
; have we already taken over this subroutine once before?
CMP WORD PTR DS:[2844h],SEG PRINTER
JE ALREADY_SAVED
; replace the original code with a call to PRINTER to intercept prints
CMP WORD PTR DS:[2842h],OFFSET PRINTER ; two copies of INTSWAP?
JE SECOND_COPY
CMP WORD PTR DS:[2841h],8B56h ; basic loaded yet?
JNE ALREADY_SAVED ; jump if not
SECOND_COPY:
MOV BYTE PTR DS:[2841h],9Ah ; opcode is far call
MOV WORD PTR DS:[2842h],OFFSET PRINTER ; target for call
MOV WORD PTR DS:[2844h],SEG PRINTER
ALREADY_SAVED:
STI
POP AX
POP DS
POP BP
JMP DWORD PTR ORIG_INT10 ; pass clear screen to BIOS now
INTSWAP ENDP
;______________________________________________________________________________
COMMENT * PRINTER prints a character string on the screen starting
at the current cursor position. After the string is
written to the screen the cursor position is updated
to just after the string.
To use this routine, a clear screen must occur
to swap in the PRINTER routine for basic.
The COMPRINT module will take over the INT 10h and make
this module permanently resident. The user from inside
his BASIC program will clear the screen with a CLS
which will perform the vector swap.
Algorithm:
check context for simple text to screen or possibly something
more involved that basic should handle
1) backup to start of string and store character count
2) load current page from DS:[0085]
3) load current position on page from DS:[0087]
4) load attribute for string from DS:[00B5]
5) move character count to CX for use in loop
6) load type of crt display from 0000:463
7) address the screen segment
8) move string to screen while synchronizing
with horizontal retrace
9) update cursor position on screen
10) update cursor position in database at DS:[0087]
11) leave registers in manner BASIC expects
On entry
DS:[SI] points to string to write
CX contains count of characters to write
DS:[0085] contains the page to which we write
DS:[00B5] contains the attribute for the text
DS:[0087] contains the current screen location and must
be updated after print is complete
*
;______________________________________________________________________________
; Local data addressable through CS register
CHAR_COUNT LABEL WORD
DW 0
LINE_START LABEL WORD
DW 0 ; 0
DW 160 ; 1
DW 320 ; 2
DW 480 ; 3
DW 640 ; 4
DW 800 ; 5
DW 960 ; 6
DW 1120 ; 7
DW 1280 ; 8
DW 1440 ; 9
DW 1600 ; 10
DW 1760 ; 11
DW 1920 ; 12
DW 2080 ; 13
DW 2240 ; 14
DW 2400 ; 15
DW 2560 ; 16
DW 2720 ; 17
DW 2880 ; 18
DW 3040 ; 19
DW 3200 ; 20
DW 3360 ; 21
DW 3520 ; 22
DW 3680 ; 23
DW 3840 ; 24
PAGE_START LABEL WORD
DW 0
DW 4000
DW 8000
DW 12000
STARTING_PAGE LABEL WORD
DW 0
END_OF_PAGE LABEL WORD
DW 0
STARTING_LINE LABEL WORD
DW 0
RESIDUAL LABEL WORD
DW 0
LOCAL_FLAG LABEL BYTE
DB 00000000b
JUST_BLANKS EQU 00000001b ; basic wants just blanks displayed
ZERO_TAGGED EQU 00000010b ; string length unknown, tagged by 0
;______________________________________________________________________________
COMMENT *
New PRINT service routine for BASIC
Calls to routine XXXX:2841 are rerouted to this piece of code
These calls come from several places within the BASIC rutime library
We service calls from three locations: 4A07 - call to display a string
4ECE - call to display blanks
612F - call to display number
Calls from anywhere else are serviced by the original basic code.
The three labels corresponding to the three types of calls we service
are STRING_IO
REPEAT_BLANKS
NUMBER_STRING
The code labeled BASIC_IO passes the interrupt back to the basic code
for service.
*
PRINTER PROC FAR
PUSH BP
MOV BP,SP ; address the stack
MOV LOCAL_FLAG,0 ; clear the flag for string i/o
; check context for simple text to screen or possibly something
; more involved that basic should handle
CMP WORD PTR DS:[079Eh],0
JNE BASIC_IO
CMP BYTE PTR DS:[07CCh],50h ; 80 bytes per line?
JNE BASIC_IO
; CMP BYTE PTR DS:[0056h],25 ; on bottom line of screen?
; JE BASIC_IO ; if so, let basic handle it
CMP WORD PTR [BP+6],4A07h ; just regular i/o?
JE STRING_IO
CMP WORD PTR [BP+6],4ECEh ; just repeated blanks?
JE REPEAT_BLANKS
CMP WORD PTR [BP+6],612Fh ; number string?
JE NUMBER_STRING
; allow original service routine to perform I/O
BASIC_IO:
POP BP
ADD SP,4 ; clear our far call from stack
PUSH SI ; original first two statements
MOV SI,WORD PTR DS:[079Eh] ; of the basic subroutine
JMP DWORD PTR ORIG_2841 ; pass control to original routine
; ----------
; send a number string to screen
; string length is not known but end is tagged by a zero
NUMBER_STRING:
PUSH BX ; save registers used
PUSH DX
PUSH DI
PUSH ES
; ... 1) store character count and mark the flag for type of i/o
DEC SI ; backup to start of string
MOV CHAR_COUNT,80 ; always less than 80 characters
OR LOCAL_FLAG,ZERO_TAGGED
MOV RESIDUAL,CX ; restore original cx contents when done
JMP SETUP_START
; ----------
; repeated blanks sent to screen
REPEAT_BLANKS:
PUSH BX ; save registers used
PUSH DX
PUSH DI
PUSH ES
; ... 1) store character count and mark the flag for type of i/o
MOV CHAR_COUNT,CX ; save character count
OR LOCAL_FLAG,JUST_BLANKS
MOV RESIDUAL,1 ; leave one in cx register when done
JMP SETUP_START
; ----------
; write the string for basic
STRING_IO:
PUSH BX ; save registers used,
PUSH DX
PUSH DI
PUSH ES
; ... 1) backup to start of string and store character count
DEC SI ; backup to start of string
MOV CHAR_COUNT,CX ; save character count
MOV RESIDUAL,1 ; leave one in cx register when done
; ... 2) load current page from DS:[0085]
SETUP_START:
MOV BL,BYTE PTR DS:[0085h] ; load current page
SUB BH,BH
SHL BX,1 ; convert to a table offset
MOV DI,PAGE_START[BX] ; load start of page
MOV STARTING_PAGE,DI ; save the page
MOV END_OF_PAGE,DI ; save ending page pointer
ADD END_OF_PAGE,4000
; ... 3) load current position on page from DS:[0087]
MOV DX,WORD PTR DS:[0087h] ; load current position
DEC DH ; basic counts from 1 instead of 0
DEC DL ; basic counts from 1 instead of 0
MOV BL,DL ; load row number
SHL BX,1 ; two bytes per table entry
ADD DI,LINE_START[BX] ; add in start of line
MOV STARTING_LINE,DI ; store this for later
MOV DL,DH ; bring down column number
SUB DH,DH
ADD DI,DX ; add in column position
ADD DI,DX ; account for attribute bytes
; ... 4) load attribute for string from DS:[00B5]
MOV BH,BYTE PTR DS:[00B5h] ; load attribute for string
; ... 5) move character count to CX for use in loop
MOV CX,CHAR_COUNT ; load the character count
; ... 6) load type of crt display from 0000:463
SUB AX,AX ; address system memory
MOV ES,AX
MOV DX,WORD PTR ES:[463h] ; load address of display adapter
ADD DX,6 ; address crt status port
; ... 7) address the screen segment
MOV AX,0B000h ; screen seg for monochrome card
CMP DX,03DAh ; is this a graphic card?
JNE MONOCHROME
MOV AX,0B800h ; load screen seg for graphic card
MONOCHROME:
MOV ES,AX ; address the screen buffer
; ... 8) move string to screen while synchronizing
; with horizontal retrace
TEST LOCAL_FLAG,JUST_BLANKS
JZ DISPLAY_LOOP
MOV BL,20h ; load a blank
BLANK_LOOP:
CALL DISPLAY_CHAR ; display a line of blanks for basic
LOOP BLANK_LOOP
JMP UPDATE_POSITION
DISPLAY_LOOP:
LODSB ; load next character
CMP AL,20h ; special character?
JGE NOT_SPECIAL
CALL SPECIAL
JZ ANOTHER_CHAR ; if flag set, go for another character
NOT_SPECIAL:
MOV BL,AL
CLI
HSYNC_WAIT1:
IN AL,DX ; check for horizontal retrace
TEST AL,1
JNZ HSYNC_WAIT1 ; wait for retrace
HSYNC_WAIT2:
IN AL,DX ; check for horizontal retrace
TEST AL,1
JZ HSYNC_WAIT2 ; wait for retrace
MOV AX,BX
STOSW ; store character and attribute
ANOTHER_CHAR:
STI
CMP DI,END_OF_PAGE
JL NOT_SCROLLED
MOV AL,0Dh ; force a carriage return
CALL SPECIAL
NOT_SCROLLED:
LOOP DISPLAY_LOOP ; repeat cx times
; ... 9) update cursor position on screen
UPDATE_POSITION:
MOV AX,DI
SUB AX,STARTING_PAGE
SHR AX,1 ; eliminate attribute bytes
SUB DX,DX
MOV BX,80 ; divide by bytes per line
DIV BX ; quotient in AL (ROW)
; remainder in DL (COLUMN)
MOV DH,AL
MOV BH,BYTE PTR DS:[0085h] ; load page number
MOV AH,2 ; request new position
INT 10h
; ... 10) update cursor position in database at DS:[0087]
XCHG DH,DL ; basic likes this reversed
INC DH ; basic counts from 1 instead of 0
INC DL ; basic counts from 1 instead of 0
MOV WORD PTR DS:[0087h],DX
; ... 11) leave registers in manner BASIC expects
MOV CX,RESIDUAL ; let decrement instr take this to zero
; inside basic
POP ES
POP DI
POP DX
POP BX
POP BP
ADD SP,4 ; throw away offset and code segment
; from our call
POP AX ; throw away near call on stack
PUSH BASIC_SEGMENT ; and convert to a far call
PUSH AX
RET ; return to basic
PRINTER ENDP
;______________________________________________________________________________
; subroutine to handle special control characters
SPECIAL PROC NEAR
; ----------
CMP AL,0Ah ; line feed?
JE NEW_LINE
; ----------
CMP AL,0Bh ; home?
JNE NOT_HOME
MOV DI,STARTING_PAGE ; start over at top of screen
MOV STARTING_LINE,DI
SUB AL,AL
RET
NOT_HOME:
; ----------
CMP AL,0Ch ; clear screen?
JNE NOT_CLEAR
MOV DI,STARTING_PAGE
MOV STARTING_LINE,DI
MOV AL,0 ; clear whole window
JMP SHORT SCROLL_SCREEN
NOT_CLEAR:
; ----------
CMP AL,0Dh ; carriage return?
JNE NOT_CR
NEW_LINE:
MOV DI,STARTING_LINE
ADD DI,160
JMP SHORT TEST_RIGHT
NOT_CR:
; ----------
CMP AL,1Ch ; move right?
JNE NOT_RIGHT
ADD DI,2
JMP SHORT TEST_RIGHT
NOT_RIGHT:
; ----------
CMP AL,1Dh ; move left?
JNE NOT_LEFT
SUB DI,2
JMP SHORT TEST_LEFT
NOT_LEFT:
; ----------
CMP AL,1Eh ; move up?
JNE NOT_UP
SUB DI,160
JMP SHORT TEST_LEFT
NOT_UP:
; ----------
CMP AL,1Fh ; move down?
JNE NOT_DOWN
ADD DI,160
JMP SHORT TEST_RIGHT
NOT_DOWN:
JMP SHORT TEST_FOR_TAB
; ----------
TEST_RIGHT:
CMP DI,END_OF_PAGE ; are we past line 25?
JL VALID_RIGHT
MOV DI,STARTING_PAGE ; back at start of last line
ADD DI,3840
MOV STARTING_LINE,DI
MOV AL,1 ; scroll one line
JMP SHORT SCROLL_SCREEN
VALID_RIGHT:
SUB AL,AL
RET
; ----------
SCROLL_SCREEN:
PUSH CX
MOV CX,0 ; start in upper left corner
PUSH DX
MOV DX,184Fh ; end in lower right
MOV AH,6
PUSHF ; simulate an INT 10
CALL DWORD PTR ORIG_INT10
POP DX
POP CX
SUB AL,AL
RET
; ----------
TEST_LEFT:
CMP DI,STARTING_PAGE
JGE VALID_LEFT
MOV DI,STARTING_PAGE
VALID_LEFT:
SUB AL,AL
RET
; ----------
TEST_FOR_TAB:
CMP AL,09h ; tab?
JNE NOT_TAB
PUSH CX
PUSH DX
MOV AX,DI
SUB AX,STARTING_LINE
SHR AX,1 ; discount attribute bytes
SUB DX,DX
MOV CX,8
DIV CX
MOV CX,8 ; tab positions are every 8 charactes
SUB CX,DX ; subtract off remainder
MOV BL,' ' ; write some blanks
POP DX
TAB_LOOP:
CALL DISPLAY_CHAR
LOOP TAB_LOOP
POP CX
SUB AL,AL
RET
NOT_TAB:
; ----------
CMP AL,08h ; backspace?
JNE NOT_BACKSPACE
CMP DI,STARTING_LINE
JE AT_START
SUB DI,2 ; back up a space
AT_START:
MOV BL,' ' ; write a blank
CALL DISPLAY_CHAR
SUB DI,2 ; back up a space
SUB AL,AL
RET
NOT_BACKSPACE:
; ----------
CMP AL,00h ; null?
JNE NOT_NULL
TEST LOCAL_FLAG,ZERO_TAGGED ; does this mean end of string?
JZ NOT_NULL ; branch if null meaningless
MOV CX,1 ; terminate the display loop
DEC SI ; backup so basic can see null too
SUB AL,AL
RET
NOT_NULL:
; ----------
MOV AH,2
SUB AH,1 ; set flag to display the char
RET
SPECIAL ENDP
;______________________________________________________________________________
; routine to display a character in BL - used only for special characters
; attribute is in BH
DISPLAY_CHAR PROC NEAR
CLI
HSYNC_WAIT3:
IN AL,DX ; check for horizontal retrace
TEST AL,1
JNZ HSYNC_WAIT3 ; wait for retrace
HSYNC_WAIT4:
IN AL,DX ; check for horizontal retrace
TEST AL,1
JZ HSYNC_WAIT4 ; wait for retrace
MOV AX,BX
STOSW ; store character and attribute
STI
RET
DISPLAY_CHAR ENDP
;______________________________________________________________________________
LASTADDR LABEL BYTE
COPYRIGHT LABEL BYTE
DB 10,13
DB ' CLUBware (tm)',10,13,10,13
DB 'COMPRINT - Enhancement to the Basic Compiler Print statement'
DB 10,13
DB ' (for routines compiled without /O option)'
DB 10,13,10,13
DB ' Copyright 1984 Rayhawk Automation N.W. Inc',10,13
DB ' P.O. Box 1427',10,13
DB ' Beaverton, Oregon 97075',10,13,'$'
;______________________________________________________________________________
COMPRINT PROC FAR
PUSH DS ; Push addr of Program Segment Prefix
SUB AX,AX ; Zero AX
PUSH AX ; Push zero onto stack
; (offset of INT 20 within PSP)
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | take over the INT 10h |
; | interrupt if not already done |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV DS,AX ; address low memory
; CMP WORD PTR DS:[40h],OFFSET INTSWAP
; JE ALREADY_DONE
MOV AX,WORD PTR DS:[40h] ; save original int10
MOV ORIG_INT10,AX
MOV AX,WORD PTR DS:[42h]
MOV ORIG_INT10+2,AX
MOV AX,SEG COMPRINT
MOV DS,AX
MOV DX,OFFSET INTSWAP ; Load offset of interrupt service mod
MOV AX,2510h ; Prepare for DOS service call type 25
; to establish service for INT 10
INT 21h ; Ask DOS to establish service
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | issue copyright message |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV DX,OFFSET COPYRIGHT
MOV AH,9
INT 21h
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | modify INT 20 into INT 27 in the |
; | program segment prefix |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | 6) load address of ending tag into DX |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
MOV AX,SEG LASTADDR
SUB AX,SEG COMPRINT
MOV CL,4 ; prepare for 4 bit shift
SHL AX,CL ; shift up (convert from seg to abs)
ADD AX,OFFSET LASTADDR ; add address of bottom location
ADD AX,0103h ; Pad offset because DOS measures
; offset relative to Program
; Segment Prefix
MOV DX,AX ; leave where DOS will find it
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
; | |
; | 7) use RET FAR to return to DOS and |
; | leave service routine resident |
; | |
; | - - - - - - - - - - - - - - - - - - - - - - - - -|
ALREADY_DONE:
RET
COMPRINT ENDP
SCRDSEG ENDS
;______________________________________________________________________________
STACK SEGMENT PARA STACK 'STACK'
DB 24 DUP('STACK***')
TOPSTACK DB 0
STACK ENDS
END COMPRINT